/*
	Copyright (c) 2010 <copyright holders>
	This source code is licensed under The MIT License,
	see the file LICENSE for details.
	*/

#include "Client.hpp"

#include <boost/lexical_cast.hpp>
#include <boost/asio/ip/tcp.hpp>

#include "ClientLogic.hpp"
#include "gen/netmsg.pb.h"

namespace spelprog2 {
namespace net {

using namespace boost::asio::ip;

Client::Client(const std::string & host, unsigned port, const std::string & password, const std::string & username) : Net(false),
    peer_(),
    internalRegistry_(),
    myUserId_()
{
    using namespace client_logic;

    internalRegistry_.addUnhandledMsgListener(                  net::NetMessageListener::Pointer(new PassOn(*this)));
    internalRegistry_.addMsgListener<netmsg::LoginReply>(       net::NetMessageListener::Pointer(new HandleLogin(*this)));
    internalRegistry_.addMsgListener<netmsg::ServerVarChange>(  net::NetMessageListener::Pointer(new HandleVarChange(*this)));
    internalRegistry_.addMsgListener<netmsg::UserChange>(       net::NetMessageListener::Pointer(new HandleUserChange(*this)));

    connect(host, port, password, username);
}

Client::~Client()
{
}

void Client::connect(const std::string & host, unsigned port, const std::string & password, const std::string & username) {
    tcp::resolver resolver(getService());
    tcp::resolver::query query(host, boost::lexical_cast<std::string>(port),
        tcp::resolver::query::numeric_service | tcp::resolver::query::address_configured);

    Connection::Pointer conn = Connection::create(getService(), this, internalRegistry_);
    boost::system::error_code error = boost::asio::error::host_not_found;

    netlog << "Resolving query for " + host + ":" + boost::lexical_cast<std::string>(port);
    for (tcp::resolver::iterator it = resolver.resolve(query), end; error && it != end; ++it) {
        conn->getSocket().close();
        conn->getSocket().connect(*it, error);
    }

    if (error) {
        throw NetException("Unable to find host " + host + ":" +
            boost::lexical_cast<std::string>(port), WHERE);
    }

    peer_= conn;
    peer_->start(SERVER_ID);

    //send login request
    netlog << "Sending login request";
    netmsg::LoginRequest loginReq;
    loginReq.set_username(username);
    loginReq.set_password(password);
    sendToUser(loginReq, SERVER_ID);
}

void Client::setUserId(UserId id)
{
    myUserId_ = id;
}

UserId Client::getMyClientId() const
{
    return myUserId_;
}

void Client::sendToUser(const Message & msg, UserId dest)
{
    //TODO: see if there's any use for sending a recipent ID, probably not
    if (dest == SERVER_ID) {
        peer_->sendMessage(msg);
    }
}

void Client::sendToAll(const Message & msg)
{
    throw Exception(0, "Unimplemented", WHERE);
}

}; //namespace net
}; //namespace spelprog2
